/**
* Author: 	XU Songgang 
* Email: 	sxu@ust.hk
*
*/

#ifndef _MATRIX_TEST_
#define _MATRIX_TEST_


#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <cstdlib>
#include "global.h"
#include "assert.hpp"
#include "../Matrix.h"

void Matrix_construction ()
{
	Matrix <int> matrix01;
	Matrix <int> matrix02 (matrix01);
	ASSERT (matrix01 == matrix02);

	unsigned row = 3;
	unsigned col = 2;
	Matrix <int> matrix03 (3,2);
	Matrix <int> matrix04 = matrix03;
	ASSERT (matrix04 == matrix03);

	const Matrix <float> matrix05 (3,4);
	Matrix <float> matrix06(matrix05);
	ASSERT (matrix06 == matrix05);
	ASSERT (!(matrix06 != matrix05));

	Matrix <float> matrix07 (1000, 1001);
	Matrix <float> matrix08 (1001, 1000);
	ASSERT (matrix07 != matrix08);

	Matrix <float> matrix09 (1001, 1000);
	Matrix <float> matrix10 (1,2);

	ASSERT (matrix10 != matrix09);
	matrix10 = matrix09;
	ASSERT (matrix10 == matrix09);
	ASSERT (1001 == matrix10.getRowSize());
	ASSERT (1000 == matrix10.getColSize());
}
void Matrix_subscript_operator()
{
	Matrix <int> matrix01(100,110);
	for (int i = 0; i< 100; ++i)
	{
		for (int j = 0; j < 110; ++j)
		{
			matrix01(i,j) = i * 110 + j;
			ASSERT (i * 110 + j == matrix01(i,j));
		}
	}

	Matrix <float> matrix02(10001, 10000);
	matrix02(10000,9999) = 3.14f;
	matrix02(0,0) = 3.14f;
	ASSERT(matrix02(10000,9999) == matrix02(0,0));

	Matrix <float> matrix03(1000001, 1);
	matrix03(1000000,0) = 2.71f;
	ASSERT(matrix03(1000000,0) == 2.71f);

}

void Matrix_equal_unequal_operator()
{
	Matrix <int> matrix01(2,3);
	Matrix <int> matrix02 = matrix01;
	ASSERT (matrix01 == matrix02);
	Matrix <int> matrix03 = matrix01;
	matrix03 (1,2) = 1;
	ASSERT (matrix01 != matrix03);
}

void Matrix_plus_operator ()
{
	Matrix <int> matrix01(2,3);
	for (int i = 0;i < matrix01.getRowSize(); ++i)
	{
		for (int j = 0; j < matrix01.getColSize(); ++j)
		{
			matrix01(i,j) = i* matrix01.getRowSize() + j;
		}
	}
	Matrix <int> matrix02 = matrix01 + matrix01 ;
	Matrix <int> matrix03 = matrix02 + matrix01;
	ASSERT (matrix03 == matrix01 + matrix02);

	Matrix <int> matrix04(1000001,1);
	Matrix <int> matrix05(matrix04);
	Matrix <int> matrix06(1000001,1);
	for (int i = 0;i < matrix04.getRowSize(); ++i)
	{
		matrix05(i,0) = - matrix05(i,0);
		matrix06(i,0) = 0;
	}

	ASSERT (matrix04 + matrix05 == matrix06);
	
	
}

void Matrix_minus_operator()
{
	Matrix <int> matrix01(2,3);
	for (int i = 0;i < matrix01.getRowSize(); ++i)
	{
		for (int j = 0; j < matrix01.getColSize(); ++j)
		{
			matrix01(i,j) = i* matrix01.getRowSize() + j;
		}
	}
	Matrix <int> matrix02 = matrix01 + matrix01 ;
	Matrix <int> matrix03 = matrix02 - matrix01;
	ASSERT (matrix03 == matrix01);

        Matrix <int> matrix04(1000001,1);
        Matrix <int> matrix05(matrix04);
        Matrix <int> matrix06(1000001,1);
        for (int i = 0;i < matrix04.getRowSize(); ++i)
        {
                matrix06(i,0) = 0;
        }

        ASSERT (matrix04 - matrix05 == matrix06);

}

void Matrix_scale_product()
{
	Matrix <int> matrix01(2,3);
	for (int i = 0;i < matrix01.getRowSize(); ++i)
	{
		for (int j = 0; j < matrix01.getColSize(); ++j)
		{
			matrix01(i,j) = i * matrix01.getRowSize() + j;
		}
	}

	Matrix <int> matrix02 = matrix01 + matrix01;
	ASSERT (matrix02 == matrix01 * 2);

	Matrix <int> matrix03(1000001, 1);
	for (int i = 0; i < matrix03.getRowSize(); ++i)
	{
		matrix03(i, 0) = 1;
	}

	Matrix <int> matrix04(matrix03);
	matrix04 = matrix04 * 2;
	ASSERT (matrix04 == matrix03 + matrix03);
}
void Matrix_matrix_product()
{
	Matrix <int> matrix01(10,10);
	for (int i = 0;i < matrix01.getRowSize(); ++i)
	{
		for (int j = i; j < matrix01.getColSize(); ++j)
		{
			if (j == i ) 
			{
				matrix01(i,j) = 1;
			}
			else
			{
				matrix01(i,j) = i* matrix01.getRowSize() + j;
				matrix01(j,i) = i* matrix01.getRowSize() + j;
			}
		}
	}
	Matrix <int> matrix02 = matrix01 + matrix01;
	ASSERT (matrix02 * matrix01 == matrix01 * matrix02);

	Matrix <int> matrix03(1,10);
	Matrix <int> matrix04(10,1);
	for (int i = 0; i < 10; ++i)
	{
		matrix03(0,i) = 1;
		matrix04(i,0) = 2;
	}
	Matrix <int> matrix05(2,2);
	matrix05 = matrix03 * matrix04;
	ASSERT (1 == matrix05.getRowSize());	
	ASSERT (1 == matrix05.getColSize());
	ASSERT (20 == matrix05(0,0));

	Matrix <int> matrix06(1, 1000000);
	Matrix <int> matrix07(1000000, 1);
	for (int i = 0; i < 1000000; ++i)
	{
		matrix06(0, i) = 1;
		matrix07(i, 0) = 1;
	}	
	Matrix <int> matrix08(matrix06 * matrix07);
	ASSERT (1 == matrix08.getRowSize());
	ASSERT (1 == matrix08.getColSize());
	ASSERT (1000000 == matrix08(0,0));
}
void Matrix_divide_operator()
{
	Matrix <int> matrix01(2,3);
	for (int i = 0;i < matrix01.getRowSize(); ++i)
	{
		for (int j = 0; j < matrix01.getColSize(); ++j)
		{
			matrix01(i,j) = i* matrix01.getRowSize() + j;
		}
	}
	Matrix <int> matrix02 = matrix01 * 2 ;
	ASSERT (matrix01 == matrix02 / 2);

	Matrix <int> matrix03(1,1);
	matrix03(0,0) = 1;
	Matrix <int> matrix04(50,50);
	matrix04 = matrix03 / 2;
	ASSERT (1 == matrix04.getRowSize());
	ASSERT (1 == matrix04.getColSize());
	ASSERT (0 == matrix04(0,0));

	Matrix <float> matrix05(1,1);
	matrix05(0,0) = 1.0f;
	matrix05 = matrix05 / 2.0f;
	ASSERT (0.5f == matrix05(0,0));

	Matrix <int> matrix06(1, 1000000);
	for (int i = 0; i < 1000000; ++i)
	{
		matrix06(0,i) = 0;
	}
	matrix06 = matrix06 / 0xFFFF;
	for (int i = 0; i < 1000000; ++i)
	{
		ASSERT (0 == matrix06(0,i));
	}
}
void Matrix_stream()
{
	string input_string = "1 2 3 4 5 6";
	stringstream isstr (stringstream::in | stringstream::out);
	stringstream osstr (stringstream::in | stringstream::out);
	isstr << input_string;

	Matrix <int> matrix01 (2,3);
	isstr >> matrix01; 

	Matrix <int> matrix02 (2,3);
	osstr << matrix01;
	osstr >> matrix02;

	ASSERT (2 == matrix01(0,1) );
	ASSERT (matrix01 == matrix02);
}
void Matrix_getrowsize()
{
	unsigned row = 2;
	unsigned col = 3;
	Matrix<int> matrix01(row, col);
	ASSERT (matrix01.getRowSize() == row);
	
	row = 1000000;
	col = 2;
	Matrix<float> matrix02(row, col);
	ASSERT (matrix02.getRowSize() == row);
}
void Matrix_getcolsize()
{
	unsigned row = 2;
	unsigned col = 3;
	Matrix<int> matrix01(row, col);
	ASSERT (matrix01.getColSize() == col);

	row = 2;
	col = 1000000;
	Matrix<float> matrix02(row,col);
	ASSERT (matrix02.getColSize() == col);
}
void Matrix_test_suite()
{
        TEST_SUITE_BEGIN("Matrix_test_suite");
/*
        TEST(Matrix_construction());            //6
        TEST(Matrix_subscript_operator());      //6
        TEST(Matrix_plus_operator());           //5
        TEST(Matrix_minus_operator());          //5
        TEST(Matrix_scale_product());           //6
        TEST(Matrix_matrix_product());          //6
        TEST(Matrix_divide_operator());         //6
        TEST(Matrix_stream());                  //6
        TEST(Matrix_getrowsize());              //2
        TEST(Matrix_getcolsize());              //2
*/
        TEST_SUITE_END();
}
#endif
